#include "stdafx.h"
#include "ActiveObject.h"
#include "LocalEndpoint.h"
#include "InvokeEndpoint.h"
#include "WindowsUtility.h"
#include "SimpleLogger.h"
#include "DynamicBindingManager.h"

namespace RoomFW {

ActiveObject::ActiveObject(size_t portCount, const PortPriorityArray& portPriority) :
	timerPortIndex_(portCount),
	endpoints_(portCount),
	replyEndpoints_(portCount),
	timerIdMgr_(),
	timer_(&timerIdMgr_),
#if ACTIVE_OBJECT_TIMER_THREADS
	timerThreads_(),
#endif
	stopEvent_(),
	portPriority_(portPriority),
	messageQueue_(),
	queueEvent_(),
	queueSynch_(),
	messageHanderMap_(),
	dynamicPortRegistered_(false)
{
//	G_LOG_1_TRACE("ActiveObject::ActiveObject: portCount=%u", portCount);

	ASSERT(portPriority.size() == portCount + 1);
}

ActiveObject::~ActiveObject()
{
	this->stop(); // Before synch object destructors.
	replyEndpoints_.clearAll();
	this->unregisterDynamicPorts();
}

void ActiveObject::mapMessageHandler(const PortIndex& portIndex, MessageHandler::Ptr handler)
{
	CriticalSectionGuard guard(queueSynch_);
	messageHanderMap_.insert(MessageHanderMap::value_type(portIndex, handler));
}

void ActiveObject::unMapMessageHandler(const PortIndex& portIndex, MessageHandler::Ptr handler)
{
	CriticalSectionGuard guard(queueSynch_);
	MessageHanderMap::iterator i = messageHanderMap_.find(portIndex);
	while ((messageHanderMap_.end() != i) && (portIndex == i->first) && (handler.get() != i->second.get()))
	{
		++i;
	}
	if ((messageHanderMap_.end() != i) && (portIndex == i->first) && (handler.get() == i->second.get()))
	{
		messageHanderMap_.erase(i);
	}
}

void ActiveObject::clearMessageHandlers()
{
	messageHanderMap_.clear();
}

std::string ActiveObject::defaultDynamicPortName(PortIndex::PrimaryIndex port) const
{
	std::stringstream str;
	str << this->getObjectName() << '_' << this->getPortName(port);
	return str.str();
}

IEndPointSP ActiveObject::getEndPoint(PortIndex::PrimaryIndex portPrimaryIndex)
{
//	G_LOG_1_TRACE("ActiveObject::getEndPoint: portIndex=%u", portPrimaryIndex);

	LocalEndPointSP retVal(new LocalEndPoint(this, portPrimaryIndex));
	size_t replication = replyEndpoints_.add(portPrimaryIndex, retVal);
	if (PortIndex::REPLICATION_BROADCAST != replication)
	{
		retVal->setReplication(replication);
	}
	else
	{
		retVal.reset();
	}
	return retVal;
}

bool ActiveObject::setEndPoint(PortIndex& portIndex, IEndPointSP endPoint)
{
//	G_LOG_2_TRACE("ActiveObject::setEndPoint: portIndex=[%d,%d]", portIndex.port(), portIndex.replication());

	ASSERT(portIndex.port() < endpoints_.size());

	bool retVal = false;
	size_t replication = endpoints_.add(portIndex.port(), endPoint);
	if (PortIndex::REPLICATION_BROADCAST != replication)
	{
		portIndex.replication(replication);
		retVal = true;
	}
	return retVal;
}

bool ActiveObject::clearEndPoint(const PortIndex& portIndex)
{
//	G_LOG_2_TRACE("ActiveObject::clearEndPoint: portIndex=[%d,%d]", portIndex.port(), portIndex.replication());

	ASSERT(portIndex.port() < endpoints_.size());
	ASSERT(portIndex.replication() < endpoints_.replicationSize(portIndex.port()));
	return endpoints_.clear(portIndex.port(), portIndex.replication());
}

void ActiveObject::put(RoomMessageSP message)
{
	const PortIndex::PrimaryIndex port = message->portIndex().port();
	const PortIndex::ReplicationIndex replication = message->portIndex().replication();
	IContractCheckerSPC protocol;
	if (timerPortIndex_ != port)
	{
		protocol = this->getContractChecker(port);
	}

	// Logging.
#ifndef G_NO_LV_MESSAGE
	if (G_IS_LOGGING_MESSAGE && protocol && protocol->getIsLogged())
	{
		std::stringstream logStr;
		logStr << '<' << message->senderName() << '>';
		logStr << '<' << this->getObjectName() << '>';
		logStr << '<' << this->getPortName(port) << '>';
		if (PortIndex::REPLICATION_BROADCAST == replication)
		{
			logStr << '<' << "BROADCAST" << '>';
		}
		else
		{
			logStr << '<' << replication << '>';
		}
		if (protocol)
		{
			logStr << '<' << protocol->messageName(message->messageID()) << '>';
		}
		else
		{
			logStr << '<' << "TIMER" << '>';
		}
		if (0 == message->payload())
		{
			logStr << '<' << "NULL" << '>';
		}
		else
		{
			logStr << '<' << message->payload()->toString() << '>';
		}
		G_LOG_0_MESSAGE(logStr.str().c_str());
	}
#endif

	// Queue the message based on port priority.
	{
		CriticalSectionGuard guard(queueSynch_);
		MessageQueue::reverse_iterator i = messageQueue_.rbegin();
		if (port < portPriority_.size()) // Ignore port priority if invalid (due to this->put()?)
		{
			const PortPriority msgPri = portPriority_[port];
			while ((messageQueue_.rend() != i) &&
				   (msgPri > portPriority_[(*i)->portIndex().port()]))
			{
				++i;
			}
		}
		// The the dereference operator returns *--tmp(base()), so this is the correct insertion point.
		messageQueue_.insert(i.base(), message);

		if (0 != queueEvent_) // Can't set event until thread started.  Event created signaled.
		{
			VERIFY(queueEvent_.set());
		}
	}
}

std::string ActiveObject::errorMessage()
{
	std::stringstream errMsg;
	if (this->isErrored())
	{
		errMsg << this->getObjectName() << ": " << IActiveObject::errorMessage();
	}
	return errMsg.str();
}

ErrorHandling::IErrorSP ActiveObject::getError()
{
	ErrorHandling::IErrorSP retVal;
	if (this->isErrored())
	{
		retVal = IActiveObject::getError();
		if (0 == retVal)
		{
			retVal.reset(new ErrorHandling::BaseError(ErrorHandling::EID_FND_UNHANDLED_EXCEPTION, ErrorHandling::ESEVfatal, this->errorMessage().c_str()));
		}
	}
	return retVal;
}

const char* ActiveObject::getThreadName() const
{
	return this->getObjectName();
}

bool ActiveObject::initializeObject()
{
	return (timer_.initialize(MAXIMUM_WAIT_OBJECTS - EventCount - this->waitHandleSize()) &&
			stopEvent_.create(true) && // Manual reset to share with invoke endpoint.
			queueEvent_.create(false, true));
}

void ActiveObject::main()
{
	for(;;) // Loop until break.
	{
		// Declare and reserve handle array to wait on.
		HandleArray handles;
		handles.reserve(timer_.size() + EventCount + this->waitHandleSize());

		// Add stop and message events.
		handles.push_back(stopEvent_);
		handles.push_back(queueEvent_);

		// Allow derived objects to add events.
		this->getWaitHandles(handles);

		// Add timer events.
		timer_.addHandles(handles);

		// Wait for an event.
		DWORD ret = ::WaitForMultipleObjectsEx((DWORD)(handles.size()), &(handles.front()), false, INFINITE, false);
		SHOW_LAST_ERROR((WAIT_FAILED != ret), "ActiveObject::main", "::WaitForMultipleObjectsEx");

		// Skip stop event, will break below.  Check for message event.
		if ((WAIT_OBJECT_0 + 1) == ret)
		{
			G_LOG_1_SPEED2("Beginning %s Handle", this->getObjectName());
			this->handleMessages();
			G_LOG_1_SPEED2("Completed %s Handle", this->getObjectName());
		}
		// Check for derived or timer events.
		else if ((ret >= (WAIT_OBJECT_0 + EventCount)) && (ret < WAIT_ABANDONED))
		{
			// Check and handle derived events.
			if (ret < (WAIT_OBJECT_0 + EventCount + this->waitHandleSize()))
			{
				this->handleEvent(handles[ret - WAIT_OBJECT_0]);
			}
			else // Handle timer events.
			{
				timer_.signal(handles[ret - WAIT_OBJECT_0]);
			}
		}
		else
		{
			break; // Anything else exits thread.
		}
	}
}

void ActiveObject::signalStop()
{
#if ACTIVE_OBJECT_TIMER_THREADS
	timerThreads_.clear();
#endif
	stopEvent_.set();
}

bool ActiveObject::isBound(const PortIndex& portIndex) const
{
	bool retVal = false;
	if (portIndex.port() < endpoints_.size())
	{
		if (portIndex.replication() != PortIndex::REPLICATION_BROADCAST)
		{
			if (portIndex.replication() < endpoints_.replicationSize(portIndex.port()))
			{
				retVal = (0 != endpoints_.get(portIndex.port(), portIndex.replication()));
			}
		}
		else
		{
			const size_t replicationSize = endpoints_.replicationSize(portIndex.port());
			for (size_t iReplication = 0; iReplication < replicationSize; ++iReplication)
			{
				if (0 != endpoints_.get(portIndex.port(), iReplication))
				{
					retVal = true;
					break;
				}
			}
		}
	}
	return retVal;
}

size_t ActiveObject::replicationCount(PortIndex::PrimaryIndex port) const
{
	return endpoints_.replicationCount(port);
}

PortIndex ActiveObject::getFirstBound(PortIndex::PrimaryIndex port) const
{
	PortIndex retVal(port);
	const size_t replicationSize = endpoints_.replicationSize(port);
	for (size_t iReplication = 0; iReplication < replicationSize; ++iReplication)
	{
		if (0 != endpoints_.get(port, iReplication))
		{
			retVal.replication(iReplication);
			break;
		}
	}
	return retVal;
}

bool ActiveObject::getNextBound(PortIndex& portIndex) const
{
	bool retVal = false;
	const size_t replicationSize = endpoints_.replicationSize(portIndex.port());
	for (size_t iReplication = (portIndex.replication() + 1); iReplication < replicationSize; ++iReplication)
	{
		if (0 != endpoints_.get(portIndex.port(), iReplication))
		{
			portIndex.replication(iReplication);
			retVal = true;
			break;
		}
	}
	if (!retVal)
	{
		portIndex.replication(PortIndex::REPLICATION_BROADCAST);
	}
	return retVal;
}

void ActiveObject::preSend(PortIndex& portIndex, MessageID messageID, IPayloadSP& payload, bool isInvoke) const
{
	// Check for valid port.  Failure here is a programming error, hence the assertion.
	ASSERT(portIndex.port() < endpoints_.size());
	if (portIndex.port() >= endpoints_.size())
	{
		throw SendMessageError(
			this->getObjectName(),
			portIndex,
			messageID,
			payload,
			SendMessageError::SMER_INVALID_PORT);
	}
	// Check for port bound.    Failure here is a programming error, hence the assertion.
	ASSERT(this->isBound(portIndex));
	if (!this->isBound(portIndex))
	{
		throw SendMessageError(
				this->getObjectName(),
				portIndex,
				messageID,
				payload,
				SendMessageError::SMER_PORT_NOT_BOUND);
	}
	// If "broadcasting" to one replication, set the replication index to first (only) bound.
	if ((portIndex.replication() == PortIndex::REPLICATION_BROADCAST) &&
		(this->replicationCount(portIndex.port()) == 1))
	{
		portIndex.replication(this->getFirstBound(portIndex.port()).replication());
	}

	// Check for broadcast invoke.
	if (portIndex.replication() == PortIndex::REPLICATION_BROADCAST)
	{
		// Can't broadcast invoke due to design of single reply.
		// This is a programming error, hence the assertion.
		ASSERT(!isInvoke);
		if (isInvoke)
		{
			throw SendMessageError(
					this->getObjectName(),
					portIndex,
					messageID,
					payload,
					SendMessageError::SMER_BROADCAST_INVOKE);
		}
	}
}

void ActiveObject::finalSend(const PortIndex& portIndex,
							MessageID messageID,
							IPayloadSP& payload,
							IEndPointSP replyEndpoint) const
{
	ASSERT(portIndex.replication() != PortIndex::REPLICATION_BROADCAST); // By this class.

	IEndPointSP ep = endpoints_.get(portIndex.port(), portIndex.replication());
	ASSERT(0 != ep); // Else preSend(), sendMessage(), or invoke() failed.

	SendMessageError::Reason reason =
		ep->acceptMessage(messageID, payload, (G_IS_LOGGING_MESSAGE ? this->getObjectName() : ""), replyEndpoint);
	if (SendMessageError::SMER_NONE != reason)
	{
		throw SendMessageError(
				this->getObjectName(),
				portIndex,
				messageID,
				payload,
				reason);
	}
}

void ActiveObject::sendMessage(const PortIndex& _portIndex, MessageID messageID, IPayloadSP payload)
{
	// Catch SendMessageError's to fill in port and message text and re-throw
	try
	{
		// Check for errors.
		PortIndex portIndex(_portIndex); // Pre-send will update broadcast to one to unicast.
		this->preSend(portIndex, messageID, payload, false);

		// Do broadcast.
		if (portIndex.replication() == PortIndex::REPLICATION_BROADCAST)
		{
			// Send to each replication.
			PortIndex epIndex = this->getFirstBound(portIndex.port());
			do
			{
				// If there's a payload, clone it.
				IPayloadSP clonedPayload;
				if (0 != payload)
				{
					clonedPayload = payload->clone();

					// Check for null.  Broadcasting a payload that doesn't implement clone()
					// is a programming error, hence the assertion.
					ASSERT(0 != clonedPayload);
					if (0 == clonedPayload)
					{
						throw SendMessageError(
								this->getObjectName(),
								portIndex,
								messageID,
								payload,
								SendMessageError::SMER_BROADCAST_PAYLOAD);
					}
				}
				// Finally, send the message.
				this->finalSend(epIndex,
								messageID,
								IPayload::ReleaseOwnership(clonedPayload),
								this->getReplyEndPoint(epIndex));
			} while (this->getNextBound(epIndex));
		}
		// Do unicast.
		else
		{
			this->finalSend(portIndex,
							messageID,
							IPayload::ReleaseOwnership(payload),
							this->getReplyEndPoint(portIndex));
		}
	}
	catch (SendMessageError& e)
	{
		e.setObjectName(this->getObjectName());
		e.setPortIndexText(this->getPortName(_portIndex.port()));
		IContractCheckerSPC protocol = this->getContractChecker(_portIndex);
		if (0 != protocol)
		{
			e.setMessageIdText(protocol->messageName(messageID));
		}
		throw e;
	}
}

RoomMessageSP ActiveObject::invoke(uint32_t timeout,
								   const PortIndex& _portIndex,
								   MessageID messageID,
								   IPayloadSP payload,
								   bool throwOnTimeout) const
{
	// Catch SendMessageError's to fill in port and message text and re-throw
	RoomMessageSP retVal;
	try
	{
		// Check for errors.
		PortIndex portIndex(_portIndex); // Pre-send will update broadcast to one to unicast.
		this->preSend(portIndex, messageID, payload, true);

		// Create reply endpoint and send.
		std::stringstream logStr;
		logStr << '<' << this->getObjectName() << '>';
		logStr << '<' << this->getPortName(portIndex.port()) << '>';
		InvokeEndpointSP replyEndpoint(new InvokeEndpoint(portIndex, this->getContractChecker(portIndex), logStr.str().c_str(), stopEvent_));
		this->finalSend(portIndex, messageID, IPayload::ReleaseOwnership(payload), replyEndpoint);

		// Wait for reply and handle error.
		retVal = replyEndpoint->wait(timeout);
		if ((0 == retVal) && throwOnTimeout)
		{
			throw SendMessageError(
					this->getObjectName(),
					portIndex,
					messageID,
					payload,
					SendMessageError::SMER_INVOKE_TIMEOUT);
		}
	}
	catch (SendMessageError& e)
	{
		e.setObjectName(this->getObjectName());
		e.setPortIndexText(this->getPortName(_portIndex.port()));
		IContractCheckerSPC protocol = this->getContractChecker(_portIndex);
		if (0 != protocol)
		{
			e.setMessageIdText(protocol->messageName(messageID));
		}
		throw e;
	}
	return retVal;
}

RoomTimer::TimerId ActiveObject::setTimer(const TimeValue& expireIn, const TimeValue& repeatEvery)
{
	return this->setTimer(IPayloadSP(), expireIn, repeatEvery);
}

RoomTimer::TimerId ActiveObject::setTimer(IPayloadSP payload, const TimeValue& expireIn, const TimeValue& repeatEvery)
{
	RoomMessageSP message(new RoomMessage(timerPortIndex_, 0, payload));
	RoomTimer::TimerId retVal = timer_.setTimer(this, message, expireIn, repeatEvery);
#if ACTIVE_OBJECT_TIMER_THREADS
	if (RoomTimer::InvalidTimerId == retVal)
	{
		BOOST_FOREACH(RoomTimerThreadSP timerThread, timerThreads_)
		{
			retVal = timerThread->setTimer(this, message, expireIn, repeatEvery);
			if (RoomTimer::InvalidTimerId != retVal)
			{
				break;
			}
		}
		if (RoomTimer::InvalidTimerId == retVal)
		{
			RoomTimerThreadSP newTimerThread(new RoomTimerThread(&timerIdMgr_));
			if (newTimerThread->start())
			{
				G_LOG_1_TRACE("%s started new timer thread", this->getObjectName());
				retVal = newTimerThread->setTimer(this, message, expireIn, repeatEvery);
				if (RoomTimer::InvalidTimerId != retVal)
				{
					timerThreads_.push_back(newTimerThread);
				}
			}
		}
	}
#endif
	message->messageID_ = retVal;
	return retVal;
}

bool ActiveObject::cancelTimer(RoomTimer::TimerId& timerId)
{
	bool retVal = ((RoomTimer::InvalidTimerId == timerId) ||
					timer_.cancelTimer(timerId));
#if ACTIVE_OBJECT_TIMER_THREADS
	if (!retVal)
	{
		BOOST_FOREACH(RoomTimerThreadSP timerThread, timerThreads_)
		{
			retVal = timerThread->cancelTimer(timerId);
			if (retVal)
			{
				break;
			}
		}
	}
#endif
	if (retVal)
	{
		timerId = RoomTimer::InvalidTimerId;
	}
	return retVal;
}

bool ActiveObject::registerDynamicPort(PortIndex::PrimaryIndex port, const char* dynamicPortName, bool remote)
{
	dynamicPortRegistered_ = true;
	std::string registeredPortName = (0 != dynamicPortName) ? dynamicPortName : this->defaultDynamicPortName(port);
	return DynamicBindingManager::Instance().registerDynamicPort(this, port, registeredPortName.c_str(), remote);
}
bool ActiveObject::registerRemoteDynamicPort(PortIndex::PrimaryIndex port, const char* dynamicPortName)
{
	return registerDynamicPort(port, dynamicPortName, true);
}

void ActiveObject::unregisterDynamicPorts()
{
	if (dynamicPortRegistered_)
		DynamicBindingManager::Instance().unregister(this);
}


DynamicBindingSP ActiveObject::dynamicBind(PortIndex::PrimaryIndex port, const char* dynamicPortName)
{
	return DynamicBindingManager::Instance().dynamicBind(this, port, dynamicPortName);
}

size_t ActiveObject::timerPortIndex() const
{
	return timerPortIndex_;
}

void ActiveObject::handleMessages()
{
	try
	{
		RoomMessageSP message = this->pop();
		while ((0 != message) && !stopEvent_.wait(0))
		{
			// Keep trying message handlers until message has been handled.
			bool handled = false;

			// Quick optimization if there aren't any message handlers registered.
			if (!messageHanderMap_.empty())
			{
				// Look for message handler for exact (replication) port index.
				MessageHanderMap::iterator i = messageHanderMap_.find(message->portIndex());
				while (!handled && (messageHanderMap_.end() != i) && (message->portIndex() == i->first))
				{
					handled = i->second->handle(message);
					++i;
				}
				// Look for message handler for primary port index.
				if (!handled)
				{
					const PortIndex primaryIndex = message->portIndex().port();
					i = messageHanderMap_.find(primaryIndex);
					while (!handled && (messageHanderMap_.end() != i) && (primaryIndex == i->first))
					{
						handled = i->second->handle(message);
						++i;
					}
				}
				// Look for message handler for any port.
				if (!handled)
				{
					static const PortIndex anyIndex = PortIndex::INVALID;
					i = messageHanderMap_.find(anyIndex);
					while (!handled && (messageHanderMap_.end() != i) && (anyIndex == i->first))
					{
						handled = i->second->handle(message);
						++i;
					}
				}
			}
			// If not handled by message handler, try derived handle().
			if (!handled)
			{
				this->handle(message);
			}
			// Check for derived events.
			if (this->waitHandleSize() > 0)
			{
				HandleArray handles;
				this->getWaitHandles(handles);
				BOOST_FOREACH(HANDLE handle, handles)
				{
					DWORD ret = ::WaitForSingleObject(handle, 0);
					SHOW_LAST_ERROR(WAIT_FAILED != ret, "ActiveObject::handleMessages", "WaitForSingleObject");
					if (WAIT_OBJECT_0 == ret)
					{
						this->handleEvent(handle);
					}
				}
			}
			// Check for timers.
			timer_.pulse();

			// Get next message.
			message = this->pop();
		}
	}
	catch (ErrorHandling::IError& e)
	{
		e.setSourceObjectName(this->getObjectName());
		throw; // Thread will catch and log.
	}
	catch (std::exception& e)
	{
		G_LOG_1_ERROR("Forwarding exception: %s", e.what());
		throw; // Thread will catch and log.
	}
	catch (...) // You must enable SEH exceptions to catch hardware (e.g. memory access) errors.
	{
		// Double logged to get object name here.
		G_LOG_1_ERROR("%s: Unhandled Exception", this->getObjectName());
		throw;
	}
}

RoomMessageSP ActiveObject::pop()
{
	RoomMessageSP retVal;
	{
		CriticalSectionGuard guard(queueSynch_);
		if (!messageQueue_.empty())
		{
			retVal = messageQueue_.front();
			messageQueue_.pop_front();
			G_LOG_2_SPEED2("%s queueSize=%u", this->getObjectName(), messageQueue_.size());
		}
	}
	return retVal;
}

IEndPointSP ActiveObject::getReplyEndPoint(const PortIndex& portIndex)
{
	IEndPointSP retVal = replyEndpoints_.get(portIndex.port(), portIndex.replication());
	if (0 == retVal)
	{
		retVal.reset(new LocalEndPoint(this, portIndex));
		VERIFY(replyEndpoints_.set(portIndex.port(), portIndex.replication(), retVal));
	}
	return retVal;
}

ActiveObject::MessageHandler::MessageHandler(ActiveObject* parent) :
	parent_(parent)
{
}

void ActiveObject::MessageHandler::sendMessage(const PortIndex& portIndex,
											   MessageID messageID,
											   IPayloadSP payload)
{
	parent_->sendMessage(portIndex, messageID, IPayload::ReleaseOwnership(payload));
}

RoomMessageSP ActiveObject::MessageHandler::invoke(uint32_t timeout,
												   const PortIndex& portIndex,
												   MessageID messageID,
												   IPayloadSP payload,
												   bool throwOnTimeout) const
{
	return parent_->invoke(timeout, portIndex, messageID, IPayload::ReleaseOwnership(payload), throwOnTimeout);
}

RoomTimer::TimerId ActiveObject::MessageHandler::setTimer(const TimeValue& expireIn, const TimeValue& repeatEvery)
{
	return parent_->setTimer(expireIn, repeatEvery);
}

RoomTimer::TimerId ActiveObject::MessageHandler::setTimer(IPayloadSP payload, const TimeValue& expireIn, const TimeValue& repeatEvery)
{
	return parent_->setTimer(payload, expireIn, repeatEvery);
}

bool ActiveObject::MessageHandler::cancelTimer(RoomTimer::TimerId& timerId)
{
	return parent_->cancelTimer(timerId);
}

const char* ActiveObject::MessageHandler::getObjectName(void) const
{
	return parent_->getObjectName();
}

const char* ActiveObject::MessageHandler::getPortName(size_t portIndex) const
{
	return parent_->getPortName(portIndex);
}

IContractCheckerSPC ActiveObject::MessageHandler::getContractChecker(PortIndex portIndex) const
{
	return parent_->getContractChecker(portIndex);
}

PortIndex::PrimaryIndex ActiveObject::MessageHandler::getTimerPort() const
{
	return parent_->timerPortIndex_;
}

bool ActiveObject::MessageHandler::registerDynamicPort(PortIndex::PrimaryIndex port, const char* dynamicPortName, bool remote)
{
	return parent_->registerDynamicPort(port, dynamicPortName, remote);
}

bool ActiveObject::MessageHandler::registerRemoteDynamicPort(PortIndex::PrimaryIndex port, const char* dynamicPortName)
{
	return parent_->registerDynamicPort(port, dynamicPortName, true);
}

DynamicBindingSP ActiveObject::MessageHandler::dynamicBind(PortIndex::PrimaryIndex port, const char* dynamicPortName)
{
	return parent_->dynamicBind(port, dynamicPortName);
}

size_t ActiveObject::MessageHandler::timerPortIndex() const
{
	return parent_->timerPortIndex();
}

bool ActiveObject::MessageHandler::isBound(const PortIndex& portIndex) const
{
	return parent_->isBound(portIndex);
}

ActiveObject* ActiveObject::MessageHandler::getParent() const
{
	return parent_;
}

bool ActiveObject::messageQueueEmpty()
{
	bool retVal = false;
	{
		CriticalSectionGuard guard(queueSynch_);
		retVal = messageQueue_.empty();
	}
	return retVal;
}

}
